﻿/*
 * ©2009-2010 XELF
 * http://xelf.info
 */

namespace XELF.Framework {

	/// <summary>
	/// 境界箱
	/// </summary>
	public partial struct BoundingBox {
		/// <summary>
		/// 
		/// </summary>
		public Vector3 Min, Max;

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="min"></param>
		/// <param name="max"></param>
		public BoundingBox(Vector3 min, Vector3 max) {
			Min = min;
			Max = max;
		}

		static readonly BoundingBox empty = new BoundingBox(
					new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity),
					new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity));

		/// <summary>
		/// 空を表す境界箱。
		/// </summary>
		public static BoundingBox Empty { get { return empty; } }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static BoundingBox CreateFromPoints(Vector3 a, Vector3 b) {
			BoundingBox result = new BoundingBox();
			Vector3.Min(ref a, ref b, out result.Min);
			Vector3.Max(ref a, ref b, out result.Max);
			return result;
		}

		static bool QuadIntersects(float s0, float s1, float s2, float s3) {
			return (s0 < 0 && s1 < 0 && s2 >= 0 && s3 >= 0)
				|| (s0 >= 0 && s1 >= 0 && s2 < 0 && s3 < 0);
		}

		/// <summary>
		/// 直線との交差を判定する。
		/// </summary>
		/// <param name="r">直線</param>
		/// <returns>交差するときにtrue</returns>
		public bool Intersects(PluckerLine r) {
			var s01 = r.V.X - r.U.Y * Min.Z + r.U.Z * Min.Y; var s13 = r.V.Y + r.U.X * Min.Z - r.U.Z * Max.X;
			var s23 = r.V.X - r.U.Y * Min.Z + r.U.Z * Max.Y; var s02 = r.V.Y + r.U.X * Min.Z - r.U.Z * Min.X;
			var s45 = r.V.X - r.U.Y * Max.Z + r.U.Z * Min.Y; var s57 = r.V.Y + r.U.X * Max.Z - r.U.Z * Max.X;
			var s67 = r.V.X - r.U.Y * Max.Z + r.U.Z * Max.Y; var s46 = r.V.Y + r.U.X * Max.Z - r.U.Z * Min.X;
			var s04 = r.V.Z - r.U.X * Min.Y + r.U.Y * Min.X; var s15 = r.V.Z - r.U.X * Min.Y + r.U.Y * Max.X;
			var s37 = r.V.Z - r.U.X * Max.Y + r.U.Y * Max.X; var s26 = r.V.Z - r.U.X * Max.Y + r.U.Y * Min.X;

			var f0x = QuadIntersects(s01, s13, s23, s02);
			var f0y = QuadIntersects(s45, s57, s67, s46);
			var f1x = QuadIntersects(s04, s45, s15, s01);
			var f1y = QuadIntersects(s23, s37, s67, s26);
			var f0z = QuadIntersects(s02, s26, s46, s04);
			var f1z = QuadIntersects(s15, s57, s37, s13);
			return (f0x | f1x) | (f0y | f1y) | (f0z | f1z);
		}

		/// <summary>
		/// 点を含むように調整する。
		/// </summary>
		/// <param name="point">点</param>
		public void Merge(Vector3 point) {
			Vector3.Min(ref Min, ref point, out Min);
			Vector3.Max(ref Max, ref point, out Max);
		}

		/// <summary>
		/// 点が含まれるか判定する。
		/// </summary>
		/// <param name="point">点</param>
		/// <returns>含むときにtrue</returns>
		public bool Contains(Vector3 point) {
			return
				point.X >= Min.X && point.Y >= Min.Y && point.Z >= Min.Z &&
				point.X < Max.X && point.Y < Max.Y && point.Z < Max.Z;
		}
	}

}
